﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading;
using System.Runtime.Remoting;
using System.Threading.Tasks;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Diagnostics;
using System.Xml.Linq;

using King.Text;
using King.Reflection;
using King.Extensions;
using King.Text.Xml;

namespace King.Text.Css {

    public class Tag { }

    public class CssElementAttribute : Attribute {
        private string m_name;
        public CssElementAttribute(string name) {
            m_name = name;
        }
        public string Name {
            get { return m_name; }
        }
    }
    public class CssAttributeAttribute : Attribute {
        private string m_name;
        public CssAttributeAttribute() {
        }
        public CssAttributeAttribute(string name) {
            m_name = name;
        }
        public string Name {
            get { return m_name; }
        }
    }

    public static class CssLoader {
        private static Dictionary<Type, CssElementInfo> m_elements;

        static CssLoader() {
            var elements =
                from o in Assembly.GetExecutingAssembly().GetTypes()
                let attribute = o.GetAttribute<CssElementAttribute>()
                where attribute != null
                select new CssElementInfo(o, attribute);
            m_elements = elements.ToDictionary(o => o.Type);
        }

        public static IEnumerable<CssElementInfo> Elements() {
            return m_elements.Values;
        }
        public static CssElementInfo GetElement(Type type) {
            return m_elements.GetValueOrDefault(type);
        }
    }
    public sealed class CssElementInfo {
        private string m_name;
        private Type m_type;
        private IEnumerable<CAttributeInfo> m_attributes;

        internal CssElementInfo(Type type, CssElementAttribute cssAttribute) {
            m_type = type;
            m_name = cssAttribute.Name.ToLower();

            var attributes =
                from o in type.Get<PropertyInfo>(declaredOnly: true, isInstance: true)
                let attribute = o.GetAttribute<CssAttributeAttribute>()
                where attribute != null
                select new CAttributeInfo(this, o, attribute);
            m_attributes = attributes.ToList();
        }

        public Type Type {
            get { return m_type; }
        }
        public string Name {
            get { return m_name; }
        }
        public IEnumerable<CAttributeInfo> Attributes() {
            return m_attributes;
        }

        public override string ToString() {
            return m_name;
        }
    }
    public sealed class CAttributeInfo {
        private string m_name;
        private CssElementInfo m_element;
        private PropertyInfo m_property;

        internal CAttributeInfo(CssElementInfo element, PropertyInfo property, CssAttributeAttribute attribute) {
            m_element = element;
            m_name = property.Name.ToLower();
            m_property = property;
        }

        public CssElementInfo Element {
            get { return m_element; }
        }
        public PropertyInfo Property {
            get { return m_property; }
        }
        public string Name {
            get { return m_name; }
        }
        public object GetValue(object target) {
            return m_property.GetValue(target);
        }

        public override string ToString() {
            return m_element.Name + "." + m_name;
        }
    }

    public abstract class Css : TextNodes {
    }

    [CssElement("body")]
    public class CssBody : Css {
    }

    [CssElement("pre")]
    public class CssPreformatted : Css {

        protected internal override IEnumerable<object> Children(TextNodeContext context) {
            return new TextIndentReset() { base.Children(context) };
        }
    }
}
